package utils

import (
	"context"
	"encoding/base64"
	"fmt"
	"github.com/google/go-tika/tika"
	"github.com/microcosm-cc/bluemonday"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// ReadFileContent 读取文件内容，并根据不同类型的文件进行清洗
func ReadFileContent(filePath string, tikaHost string) (string, error) {
	// 判断文件地址前缀是否以http开头
	if strings.HasPrefix(filePath, "http") {
		// 下载文件
		file, err := downloadFile(filePath)
		if err != nil {
			return "", nil
		}
		filePath = file
	}
	// 创建 Tika 客户端
	client := tika.NewClient(nil, tikaHost)
	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return "", fmt.Errorf("打开文件出现错误：%v", err)
	}
	defer file.Close()
	// 使用 Tika 提取 文件的文本内容
	content, err := client.Parse(context.TODO(), file)
	if err != nil {
		return "", fmt.Errorf("提取文件内容出现错误：%v", err)
	}
	// 提取文件扩展名
	ext := filepath.Ext(filePath)
	switch ext {
	case ".doc", ".docs", ".pdf", ".pptx", "ppt":
		return cleanBlankLine(cleanHtml(content, false)), nil
	case ".xls", ".xlsx":
		return cleanBlankLine(cleanHtml(content, true)), nil
	default:
		return cleanBlankLine(content), nil
	}
}

// cleanHtml 清理HTML标签
func cleanHtml(html string, keepTable bool) string {
	var policy *bluemonday.Policy
	if keepTable {
		// 创建基础策略并显式允许表格标签（table、thead、tbody、tr、td、th）
		policy = bluemonday.NewPolicy()
		policy.AllowElements("table", "thead", "tbody", "tfoot", "tr", "td", "th")
	} else {
		// 采用严格策略 StrictPolicy()，移除所有 HTML 标签仅保留文本
		policy = bluemonday.StrictPolicy()
	}
	// 通过 policy.Sanitize(html) 执行清理，过滤非白名单内的标签及危险属性（如 onclick），防止 XSS 攻击
	return policy.Sanitize(html)
}

// cleanBlankLine 该函数旨在清理文本内容中的空行 和 图片行
func cleanBlankLine(content string) string {
	// 按照换行符分割文件
	lines := strings.Split(content, "\n")
	texts := make([]string, 0)
	for _, line := range lines {
		// TrimSpace 去除首尾空格
		line = strings.TrimSpace(line)
		if len(line) < 2 {
			continue
		}
		// 去除以图片格式结尾的行
		if strings.HasSuffix(line, ".png") ||
			strings.HasSuffix(line, ".jpg") ||
			strings.HasSuffix(line, ".jpeg") {
			continue
		}
		texts = append(texts, line)
	}
	return strings.Join(texts, "\n")
}

// downloadFile 下载文件，返回文件完整地址
func downloadFile(url string) (string, error) {
	// 提取文件路径中的最后一个元素（通常是文件名或目录名）
	base := filepath.Base(url)
	// 获取系统默认临时文件目录路径
	dir := os.TempDir()
	// 拼接完整文件地址
	filename := filepath.Join(dir, base)
	// 创建文件
	out, err := os.Create(filename)
	if err != nil {
		return "", err
	}
	defer out.Close()
	// 发送请求下载文件
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	// 写入数据到文件中
	_, err = io.Copy(out, resp.Body)
	return filename, err
}

// URLImgToBase64 图片URL转成 Base64字符串
func URLImgToBase64(imgUrl string) (base64Str string, err error) {
	// 创建带超时的HTTP客户端
	client := &http.Client{
		Timeout: 10 * time.Second,
	}

	// 发送Get请求
	resp, err := client.Get(imgUrl)
	if err != nil {
		return "", fmt.Errorf("下载图片失败：%w", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("服务器返回错误状态码：%s", resp.Status)
	}
	// 读取响应体
	imageData, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取图片数据失败：%w", err)
	}

	// 获取内容类型
	contentType := resp.Header.Get("Content-Type")
	if contentType == "" {
		// 如果响应头没有 Content-Type，尝试自动检测
		contentType = http.DetectContentType(imageData)
	}
	// 标准化图片MIME类型
	switch {
	case strings.Contains(contentType, "jpeg") || contentType == "image/jpg":
		contentType = "image/jpeg"
	case strings.Contains(contentType, "png"):
		contentType = "image/png"
	case strings.Contains(contentType, "gif"):
		contentType = "image/gif"
	case strings.Contains(contentType, "webp"):
		contentType = "image/webp"
	// 可以继续添加其他类型的处理
	default:
		return "", fmt.Errorf("不支持的图片类型: %s", contentType)
	}
	// 转换为Base64
	base64Str = base64.StdEncoding.EncodeToString(imageData)
	// 创建完整的base64格式
	base64Str = "data:" + contentType + ";base64," + base64Str
	return
}
